package com.gitee.l0km.aocache.config;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import com.gitee.l0km.aocache.AnnotationAttributes;
import com.gitee.l0km.aocache.AocacheLogger;
import com.gitee.l0km.aocache.AocacheRemovalListener;
import com.gitee.l0km.aocache.SafeStrategy;
import com.gitee.l0km.aocache.annotations.AoCacheable;
import com.google.common.cache.RemovalListener;
import com.google.common.collect.ImmutableMap;

import java.lang.reflect.Method;

public class CacheConfig extends AnnotationAttributes implements FieldConstant {
	private static final long serialVersionUID = -3704191369253862478L;
	/**
	 * 默认缓存配置实例[不可修改]
	 */
	public static final CacheConfig DEFAULT_CONFIG = new CacheConfig().immutable();
	private final AoCacheable annot;
	public CacheConfig() {
		super(AoCacheable.class);
		this.annot= synthesize();
	}
	public CacheConfig(AoCacheable annot) {
		super(annot);
		/** 
		 * NOTE: 强制禁用注解定义弱引用KEY
		 * 因为InvokeCache的Key是InvokeKey对象，该类仅在AoCache内部引用，不可能有外部强引用，
		 * 所以如果指定为Key弱引用会导致缓存值被频繁误删除
		 */
		put(WEAK_KEYS, false);
		this.annot= synthesize();
	}
	/**
	 * 从{@link AnnotationAttributes}复制数据创建一个新实例
	 * @param other
	 */
	public CacheConfig(AnnotationAttributes other) {
		this(other,other.isMutable());
	}
	/**
	 * 从{@link AnnotationAttributes}复制数据创建一个新实例
	 * @param other
	 * @param mutable 新实例是否可修改
	 */
	public CacheConfig(AnnotationAttributes other, boolean mutable) {
		super(other,mutable);
		if(other instanceof CacheConfig) {
			this.annot = ((CacheConfig)other).annot;
		}else {
			this.annot= synthesize(AoCacheable.class);
		}
	}
	public boolean debugOutput() {
		return annot.debugOutput();
	}
	public CacheConfig debugOutput(boolean debugOutput) {
		put(DEBUG_OUTPUT, debugOutput);
		return this;
	}
	public boolean debugOutputDetail() {
		return annot.debugOutputDetail();
	}
	public CacheConfig debugOutputDetail(boolean debugOutputDetail) {
		put(DEBUG_OUTPUT_DETAIL, debugOutputDetail);
		return this;
	}
	public boolean outputAroundCost() {
		return annot.outputAroundCost();
	}
	public CacheConfig outputAroundCost(boolean outputAroundCost) {
		put(OUTPUT_AROUND_COST, outputAroundCost);
		return this;
	}
	@SuppressWarnings("deprecation")
	public boolean weakKeys() {
		return annot.weakKeys();
	}
	public CacheConfig weakKeys(boolean weakKeys) {
		put(WEAK_KEYS, weakKeys);
		return this;
	}
	public boolean weakValues() {
		return annot.weakValues();
	}
	public CacheConfig weakValues(boolean weakValues) {
		put(WEAK_VALUES, weakValues);
		return this;
	}
	public boolean softValues() {
		return annot.softValues();
	}
	public CacheConfig softValues(boolean softValues) {
		put(SOFT_VALUES, softValues);
		return this;
	}
	public int initialCapacity() {
		return annot.initialCapacity();
	}
	public CacheConfig initialCapacity(int initialCapacity) {
		put(INITIAL_CAPACITY, initialCapacity);
		return this;
	}
	public int concurrencyLevel() {
		return annot.concurrencyLevel();
	}
	public CacheConfig concurrencyLevel(int concurrencyLevel) {
		put(CONCURRENCY_LEVEL, concurrencyLevel);
		return this;
	}
	public long maximumSize() {
		return annot.maximumSize();
	}
	public CacheConfig maximumSize(long maximumSize) {
		put(MAXIMUM_SIZE, maximumSize);
		return this;
	}
	public long maximumWeight() {
		return annot.maximumWeight();
	}
	public CacheConfig maximumWeight(long maximumWeight) {
		put(MAXIMUM_WEIGHT, maximumWeight);
		return this;
	}
	public long expireAfterWrite() {
		return annot.expireAfterWrite();
	}
	public CacheConfig expireAfterWrite(long expireAfterWrite,TimeUnit timeUnit) {
		put(EXPIRE_AFTER_WRITE, expireAfterWrite);
		if(null != timeUnit) {
			put(EXPIRE_AFTER_WRITE_TIMEUNIT, timeUnit);
		}
		return this;
	}
	public TimeUnit expireAfterWriteTimeUnit() {
		return annot.expireAfterWriteTimeUnit();
	}
	public long expireAfterAccess() {
		return annot.expireAfterAccess();
	}
	public CacheConfig expireAfterAccess(long expireAfterAccess,TimeUnit timeUnit) {
		put(EXPIRE_AFTER_ACCESS, expireAfterAccess);
		if(null != timeUnit) {
			put(EXPIRE_AFTER_ACCESS_TIMEUNIT, timeUnit);
		}
		return this;
	}
	public TimeUnit expireAfterAccessTimeUnit() {
		return annot.expireAfterAccessTimeUnit();
	}
	public long refreshAfterWrite() {
		return annot.refreshAfterWrite();
	}
	public CacheConfig refreshAfterWrite(long refreshAfterWrite,TimeUnit timeUnit) {
		put(REFRESH_AFTER_WRITE, refreshAfterWrite);
		if(null != timeUnit) {
			put(REFRESH_AFTER_WRITE_TIMEUNIT, timeUnit);
		}
		return this;
	}
	public TimeUnit refreshAfterWriteTimeUnit() {
		return annot.refreshAfterWriteTimeUnit();
	}

	@SuppressWarnings("unchecked")
	public<K,V> RemovalListener<K, V> removalListener() {
		return (RemovalListener<K, V>) get(REMOVAL_LISTENER);
	}

	public CacheConfig removalListener(AocacheRemovalListener<?, ?> listener) {
		if (null != listener) {
			put(REMOVAL_LISTENER, RemovalListenerWrapper.wrap(listener));
		}
		return this;
	}

	public CacheConfig removalListener(Class<? extends AocacheRemovalListener<?, ?>> listenerClass) throws InstantiationException {
		removalListener((AocacheRemovalListener<?, ?>) RemovalListenerWrapper.wrap(listenerClass));
		return this;
	}
	public boolean copyArgs() {
		return annot.copyArgs();
	}

	public CacheConfig argsSafeStrategy(boolean copyArgs) {
		put(COPY_ARGS, copyArgs);
		return this;
	}

	public SafeStrategy returnSafeStrategy() {
		return annot.returnSafeStrategy();
	}

	public CacheConfig returnSafeStrategy(SafeStrategy returnSafeStrategy) {
		put(RETURN_SAFE_STRATEGY, returnSafeStrategy);
		return this;
	}
	public CacheConfig immutable() {
		this.mutable = false;
		return this;
	}

	/**
	 * 重建一个新的 {@link CacheConfig} 实例。
	 * <p>
	 * 该方法会创建一个新的 {@code CacheConfig} 实例，
	 * 并将当前实例的所有注解属性复制到新实例的注解中，
	 * 同时保持新实例的可修改状态与当前实例一致。
	 * </p>
	 * 
	 * @return 一个包含当前实例所有属性的新 {@code CacheConfig} 实例。
	 */
	public CacheConfig rebuild(){
		CacheConfig config = new CacheConfig(this.synthesize(AoCacheable.class));
		config.putAll(this);
		config.mutable = this.mutable;
		return config;
	}

	@Override
	public CacheConfig clone() {
		return new CacheConfig(this);
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + Objects.hash(annot);
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		CacheConfig other = (CacheConfig) obj;
		return Objects.equals(annot, other.annot);
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("CacheConfig [annot=").append(annot).append(", toString()=").append(super.toString())
				.append("]");
		return builder.toString();
	}
	
    /**
     * 根据传入的对象创建一个 CacheConfig 实例。
     * <p>
     * 如果传入的对象不是 Map 类型，则返回 null。
     * <p>
     * 如果传入的对象是 Map 类型，则将 Map 中的所有键值对放入新创建的 CacheConfig 实例中。
     * 
     * @param object 用于创建 CacheConfig 实例的对象，期望为 Map 类型
     * @return 如果传入对象是 Map 类型，则返回包含该 Map 所有键值对的 CacheConfig 实例；否则返回 null
     */
    @SuppressWarnings("unchecked")
	public static CacheConfig of(Object object) {
        if(! (object instanceof Map)) {
            return null;
        }
        Map<String, Object> map = (Map<String, Object>) object;
        CacheConfig config = new CacheConfig();
        config.putAll(map);
        return config;
    }

	/**
	 * 将字符串解析为缓存配置对象对应的字段名定义。
	 * <ul>
	 * <li> null 或空字符串：返回null，代表无效配置</li>
	 * <li> "true"（不区分大小写）：返回null，代表无效配置</li>
	 * <li> "false"（不区分大小写）：返回 Boolean.FALSE，代表禁用缓存</li>
	 * <li> "{}"：返回空的不可变映射,代表默认配置</li>
	 * <li> "{key1=value1,key2=value2,...}"：返回包含键值对的不可变映射，代表缓存配置参数，如果{}中的字段名不是CacheConfig定义的字段，则忽略，否则将字段值解析为CacheConfig对应的字段类型</li>
	 * </ul>
	 * @param joinpoint 切入点，用于日志记录
	 * @param configstr 要解析的字符串
	 * @return 解析后的对象，可能是 ImmutableMap 或 Boolean.FALSE
	 *         如果解析失败或格式无效，返回null
	 */
	public static Object parseConfig(String joinpoint, String configstr) {
		// 检查输入字符串是否为null，如果是，则返回null
		if (configstr == null){
			return null;
		}
		// 移除字符串两端的空格
		configstr = configstr.trim();
		// 如果字符串为空或为"true"（不区分大小写），则返回null
		if (configstr.isEmpty() || "true".equalsIgnoreCase(configstr)) {
			return null;
		}
		// 如果字符串为"false"（不区分大小写），则返回布尔值FALSE
		if ("false".equalsIgnoreCase(configstr)) {
			return Boolean.FALSE;
		}
		// 如果字符串以"{"开始并以"}"结束，尝试解析为映射
		if (configstr.startsWith("{") && configstr.endsWith("}")) {
			ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
			String content = configstr.substring(1, configstr.length() - 1).trim();
			if (!content.isEmpty()) {
				String[] pairs = content.split(",");
				for (String pair : pairs) {
					/**
					 * 对每个键值对进行处理：
					 * 1. 移除前后的空格
					 * 2. 按":"分割键和值
					 * 3. 验证键是否有效，如果有效则尝试解析值并添加到映射构建器中
					 * 4. 如果解析失败，记录警告并忽略该字段
					 * 5. 如果键值对格式不正确，记录警告并忽略该对
					 * 6. 如果字符串不符合预期格式，记录警告并返回null
					 * 7. 返回构建好的不可变映射
					 */
					String[] keyValue = pair.split(":");
					if (keyValue.length == 2) {
						String key = keyValue[0].trim();
						String value = keyValue[1].trim();
						// 验证键是否有效，如果有效则尝试解析值并添加到映射构建器中
						if (isValidField(key)) {
							try {
								builder.put(key, parseValue(key, value));
							} catch (RuntimeException e) {
								/** 忽略解析失败的字段 */
								AocacheLogger.DEFAULT.log("WARNING:" + e.getMessage());
							}
						}else {
							AocacheLogger.DEFAULT.log("WARNING: IGNORED the key '{}:{}' for {}, that not a valid field of CacheConfig", key, value, joinpoint);
						}
					}else {
						AocacheLogger.DEFAULT.log("WARNING: IGNORED the pair {} for {}, that is not in the format key:value", pair, joinpoint);
					}
				}
			}
			return builder.build();
		}
		/**
		 * 如果字符串不符合预期格式，记录警告并返回null
		 * 1. 记录警告：输入字符串 {} 不是以"{"开始并以"}"结束的
		 */
		AocacheLogger.DEFAULT.log("WARNING: The config string '{}' for {} is not enclosed in braces { }", configstr, joinpoint);
		return null;
	}

    /**
     * 检查字段名是否是CacheConfig定义的字段
     * @param fieldName 字段名
     * @return 如果是CacheConfig定义的字段返回true，否则返回false
     */
    private static boolean isValidField(String fieldName) {
		try {
            CacheConfig.class.getMethod(fieldName);
            return true;
        } catch (NoSuchMethodException | SecurityException e) {
			return false;
		}
    }

    /**
     * 将字段值解析为CacheConfig对应的字段类型
     * @param fieldName 字段名
     * @param value 字段值
     * @return 解析后的值
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
	private static Object parseValue(String fieldName, String value) {
		try {
            Method readerMethod = CacheConfig.class.getMethod(fieldName);
            Class<?> fieldType = readerMethod.getReturnType();
            if (fieldType == String.class) {
                return value;	
            }else if (fieldType == int.class) {
                return Integer.parseInt(value);	
            }else if (fieldType == long.class) {
                return Long.parseLong(value);	
            }else if (fieldType == boolean.class) {
                return Boolean.parseBoolean(value);
            }else if (fieldType == TimeUnit.class) {
                return TimeUnit.valueOf(value);
			}else if (fieldType == Class.class) {
				return Class.forName(value);
			}else if (fieldType == Enum.class) {
				return Enum.valueOf((Class<? extends Enum>) fieldType, value);
			}
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to parse value " + value + " for field " + fieldName, e);
        }
        return value;
    }
}
